/* -*- mode: c++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil; -*- */

#ifndef _CMTPROTO_H_
#define _CMTPROTO_H_

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

#include <sys/types.h>
#include <sys/socket.h>

#include <utility.h>
#include <strhelper.h>

class CmdParser {
public:
    char                *_buf;

    char                 _cmd[128];

    char                 _key[128];

    char                 _value[1024];

    CmdParser() : _buf(NULL) {}

    bool reset(char *ptr);

    bool next();
};

class CmdConstructor {
public:
    char                *_buf;

    int                  _cap_size;

    int                  _cur_pos;

    CmdConstructor(int init_size = 1024) {
        _buf = (char *) malloc (init_size);
        _cap_size = init_size;
        _cur_pos = 0;
    }

    ~CmdConstructor() {
        free(_buf);
    }

    void append_text(const char *text, int size) {
        /* _cap_size - _cur_pos 表示 buffer 的大小
         * 这里之所以用 <= 是因为最后一个字节用来存放命令终结 \n
         */
        if (_cap_size - _cur_pos <= size) {
            if (_cap_size < size)
                _cap_size += size;
            else
                _cap_size *= 2;

            _buf = (char *) realloc(_buf, _cap_size);
        }

        memcpy(_buf + _cur_pos, text, size);

        _cur_pos += size;
    }

    char *encode(const char *p)
    {
        int size = strlen(p) * 2 + 1;

        char *buf = (char *) malloc (size);

        char *pbuf = buf;

        char c;

        while ((c = *p++) != 0) {
            switch (c) {
            default:
                *pbuf++ = c;
                break;

            case ':': case '=': case ';':
                *pbuf++ = '\\';
                *pbuf++ = c;
                break;

            case '\n':
                break;
            }
        }

        *pbuf = 0;

        return buf;
    }

    void reset(const char *cmd) {
        char cmd_cons[128];
        int  len;

        _cur_pos = 0;

        char *enc = encode(cmd);

        len = snprintf(cmd_cons, 128, "%s: ", enc);
        append_text(cmd_cons, len);

        free(enc);
    }

    void add_param(const char *key, const char *val) {
        char param_cons[1280];
        int  len;

        char *enc1 = encode(key);
        char *enc2 = encode(val);

        len = snprintf(param_cons, 1280, "%s=%s; ", enc1, enc2);

        append_text(param_cons, len);

        free(enc1);
        free(enc2);
    }

    void add_param(const char *key, int val) {
        char param_cons[128];
        int  len;

        char *enc = encode(key);

        len = snprintf(param_cons, 128, "%s=%d; ", enc, val);

        append_text(param_cons, len);

        free(enc);
    }

    void add_param(const char *key) {
        char param_cons[128];
        int  len;

        char *enc = encode(key);

        len = snprintf(param_cons, 128, "%s=; ", key);

        append_text(param_cons, len);

        free(enc);
    }

    void send_data(int fd) {
        _buf[_cur_pos] = '\n';
        send(fd, _buf, _cur_pos + 1, 0);
    }
};

class InputReceiver {
public:
    char                *_buf;

    int                  _cap_size;

    int                  _cur_pos;

    int                  _socket_status;

    enum {
        SS_NORMAL,

        SS_CLOSED,

        SS_EXCEPTION,
    };

    InputReceiver(int init_size = 1024) {
        _buf           = (char *) malloc (init_size);
        _cap_size      = init_size;
        _cur_pos       = 0;
        _socket_status = SS_NORMAL;
    }

    ~InputReceiver() {
        free(_buf);
    }

    bool is_closed() const { return _socket_status == SS_CLOSED; }

    bool is_exception() const { return _socket_status == SS_EXCEPTION; }

    void reset() {
        _socket_status = SS_NORMAL;

        _cur_pos = 0;
    }

    inline void expand_buffer() {
        _cap_size *= 2;
        _buf = (char *) realloc (_buf, _cap_size);
    }

    /* 返回新得到的数据长度
     * 这个 client fd 是统一 epoll 的。
     */
    int receive_data(int fd);

    /* 返回 buffer 中，第一个出现 c 的位置
     * 前向，如果找不到，返回 -1，如果找到，返回 index
     */
    inline int find_char_forward(char c) const {
        int i;
        for (i = 0; i < _cur_pos; i++) {
            if (_buf[i] == c)
                break;
        }
        return (i < _cur_pos) ? i : -1;
    }

    /* 丢弃前面的 N 个字节。
     * 表示这条命令已经处理完了。
     */
    inline void drop_first_nbytes(int nbytes) {
        if (nbytes < _cur_pos) {
            memmove(_buf, _buf + nbytes, _cur_pos - nbytes);
            _cur_pos -= nbytes;
        }
        else
            _cur_pos = 0;
    }
};

#endif /* _CMTPROTO_H_ */
